//  nexys3_bot_if.v - Interface to the Rojobot and picoblaze logic CPU
//  
//  Copyright Jabeer Ahmed, Caleb Methisen 2014
//
//  Created By:         Jabeer Ahmed
//  Last Modified:      TODO
//  
//  Revision History:
//   -----------------
//  TODO
//  
//  Description
//  -----------
//  This module implements a register-based interface to the Rojobot.
//  The Rojobot is implemented in a SOC embedded system using the Xilinx
//  Picoblaze as the CPU and block of logic (in verilog) to implement the world map.
//    
//  The Rojobot emulator (BOTSIM) is controlled by external logic writing to an 8-bit motor
//  control register of the following format:  
//      lm_spd[2:0], lm_dir, rm_spd[2:0], rm_dir where
//      lm_spd and rm_spd are the speed of the left and write motors
//      lm_dir and rm_dir are motor forward (1) and motor reverse (0)
//
//  A Rojobot-based system design needs access to information about the location of
//  the Rojobot in its simulated world.  This access is in the form of the following
//  8-bit registers:
//          Loc_X       O   X (column) coordinate of Rojobot's current location
//          Loc_y       O   Y (row) coordinate of Rojobot's current location
//          Sensors     O   Sensor values.  Rojobot contains a proximity sensor (left and right)
//                          A proximity sensor is set to 1 if Rojobot detects an object in
//                          front of it.  It also contains a black line sensor (left, center
//                          and right).  Each black line sensor is set to 0 if there is
//                          a black line under it and set to 1 if there is not black line
//                          under it.
//          BotInfo     O   Information on rojobot's current orientation and movement
//
//  There are two additional registers available to the Robobot-based system
//  but they aren't very useful for anything other than debug and they have been
//  deprecated and will be removed at a later date
//          LMDist      O   Left motor distance counter value
//          RMDist      O   Right motor distance counter value
//  
//  Data from the BOTSIM is stored in internal registers
//  as they are written by the PicoBlaze.  The Rojobot interface provides a synchronized
//  view of all of the registers by transferring the contents of the internal registers when
//  internal control signals are asserted by the PicoBlaze by writing the following port addresses:
//      PRW_LOADREGS,   Port Address 0C     ; loads system interface registers
//      PRW_LDMOTDIST,  Port Address 0D     ; loads motor distance counters
//      PRW_RUNNING,    Port Address 0E     ; a way for the PicoBlaze program to indicate it's running
//      Each write to the specific port toggles the control signal (which is reset to deasserted)                           
//////////


/*******************************************************************************
                                I/O PORT DECLARATION 
 ******************************************************************************/
module nexys3_bot_if(

/*************  Picoblaze *************/
    // Inputs (Read/Write)
    input               Wr_Strobe,      // Write strobe - assert to write data
                        Rd_Strobe,      // Read strobe - assert to read data
    input       [7:0]   AddrIn,         // I/O port address
    input       [7:0]   DataIn,         // Data to be written to I/O register
    input               interrupt_ack,  // TODO: interrupt acknowledge from Pico
    
    // Output
    output reg  [7:0]   DataOut,        // I/O register data to picoblaze
    output              interrupt,      // TODO: interrupt from BotSIM->Pico

/**************** BotSIM **************/    
    // Inputs (Register Interface)
    input       [7:0]   LocX,           // X-coordinate of rojobot's location       
                        LocY,           // Y-coordinate of rojobot's location
                        BotInfo,        // Rojobot orientation and movement
                        Sensors,        // Sensor readings
                        LMDist,         // Left motor distance register
                        RMDist,         // Right motor distance register
    input               upd_sysregs,    // Flag from PicoBlaze to indicate that 
                                        // the system registers (LocX, LocY, 
                                        // Sensors, BotInfo)have been updated   
    // Output   
    output reg  [7:0]   MotCtl,         // Motor control from pico->bot 
    
/*********** Segment Display **********/        
    output reg  [4:0]   dig3, dig2,     // Digits 0-3 output
                        dig1, dig0,     
    output reg  [3:0]   dp,             // Decimal Pt. output

/********* Buttons & Switches *********/
    input       [3:0]   db_btns,        // Debounced button inputs
    input       [7:0]   db_sw,          // Debounced slide switchesd            

/*************** LEDs *****************/
    output reg  [7:0]   led,            // Output to the leds       

/********** System Control ********T***/
    input               clk,            // system clock
                        reset           // system reset
);

/*******************************************************************************
                                INTERNAL VARIABLES 
 ******************************************************************************/

reg         Interrupt_FF;           // Interrupt_FF from BotSIM
wire        clear_interrupt;

assign interrupt = Interrupt_FF;
assign clear_interrupt = reset | interrupt_ack;


/*******************************************************************************
                                    PORT ADDRESSES 
 ******************************************************************************/

/********* Nexys 3 board interface ports **********/
localparam PA_PBTNS   = 4'h0;       // pushbuttons 
localparam PA_SLSWTCH = 4'h1;       // slide switches
localparam PA_LEDS    = 4'h2;       // LEDs
localparam PA_DIG3    = 4'h3;       // digit 3 PA address
localparam PA_DIG2    = 4'h4;       // digit 2 PA address
localparam PA_DIG1    = 4'h5;       // digit 1 PA address
localparam PA_DIG0    = 4'h6;       // digit 0 PA address
localparam PA_DP      = 4'h7;       // decimal points PA address
localparam PA_RSVD    = 4'h8;       // *RESERVED*

/*********** rojobot interface registers **********/
localparam PA_MOTCTL  = 4'h9;       // Rojobot motor control output from system
localparam PA_LOCX    = 4'hA;       // X coordinate of rojobot location
localparam PA_LOCY    = 4'hB;       // Y coordinate of rojobot location
localparam PA_BOTINFO = 4'hC;       // Rojobot info register
localparam PA_SENSORS = 4'hD;       // Sensor register
localparam PA_LMDIST  = 4'hE;       // Rojobot left motor distance register
localparam PA_RMDIST  = 4'hF;       // Rojobot right motor distance register
                                
/*******************************************************************************
                        PICOBLAZE <--> BOTSIM R/W LOGIC 
 ******************************************************************************/
parameter   START_ADDR = 8'h00,
            END_ADDR   = 8'h15;

assign valid_addr_range = (AddrIn >= START_ADDR) && (AddrIn <= END_ADDR);
assign write_en = Wr_Strobe & valid_addr_range;

// read registers
always @(*) begin
    case (AddrIn[3:0])
        /*************** rojobot interface registers Access **************/
        PA_LOCX     : DataOut <= LocX;      
        PA_LOCY     : DataOut <= LocY;
        PA_BOTINFO  : DataOut <= BotInfo;
        PA_SENSORS  : DataOut <= Sensors;
        PA_LMDIST   : DataOut <= LMDist;        
        PA_RMDIST   : DataOut <= RMDist;    
        /******************************/
        PA_PBTNS    : DataOut <= db_btns;
        PA_SLSWTCH  : DataOut <= db_sw;
        PA_LEDS     : DataOut <= led;
        PA_DIG3     : DataOut <= dig3;
        PA_DIG2     : DataOut <= dig2;
        PA_DIG1     : DataOut <= dig1;
        PA_DIG0     : DataOut <= dig0;
        PA_DP       : DataOut <= dp;  
        PA_RSVD     : DataOut <= 8'b0;
        PA_MOTCTL   : DataOut <= MotCtl;
    endcase
end // always - read registers

// write registers
always @(posedge clk or posedge reset) begin
    if (reset) begin
        // Clear all the registers
        MotCtl          <= 0;
        led             <= 0;
        dig3            <= 0;
        dig2            <= 0;
        dig1            <= 0;
        dig0            <= 0;
        dp              <= 0;  
    end
    else begin
        if(write_en) begin
            case (AddrIn[3:0])
                /*************** rojobot interface registers Access **************/
                PA_LOCX     : ;
                PA_LOCY     : ;
                PA_BOTINFO  : ;
                PA_SENSORS  : ;
                PA_LMDIST   : ;
                PA_RMDIST   : ;
                /******************************/
                PA_PBTNS    : ;
                PA_SLSWTCH  : ;
                PA_LEDS     : led    <= DataIn;
                PA_DIG3     : dig3   <= DataIn;
                PA_DIG2     : dig2   <= DataIn;
                PA_DIG1     : dig1   <= DataIn;
                PA_DIG0     : dig0   <= DataIn;
                PA_DP       : dp     <= DataIn;
                PA_RSVD     : ;
                PA_MOTCTL   : MotCtl <= DataIn;
            endcase
        end
    end
end
 
always @(posedge clk or posedge upd_sysregs) begin
	if (upd_sysregs)
		Interrupt_FF <= 1'b1;
	else if (clear_interrupt)
		Interrupt_FF <= 1'b0;
end 
 
endmodule